準備
HOC なDragDropContextで親コンポーネントをラップするか、DragDropContextProviderを親コンポーネントマークアップに含める必要があります。ただし、DragDropContextProviderは、react >= 16.0.0かつreact-dnd >= 4.0.0なバージョンである必要があります。
またブラウザ上で動作させる場合react-dnd-html5-backendというパッケージも必要です。イベントハンドラーのようなものがまとまったもので、これを使って色々解決する感じのようです。react-dndとreact-dnd-html5-backendは基本同じバージョンを使うようにしましょう。
ルートとしては以下のようになります。
DragDropContextProvider
import React from 'react';
import {DragDropContextProvider} from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
class App extends React.Component {
render() {
return (
なんでもいい
);
}
}
export default App;DragDropContext
import React from 'react';
import {DragDropContext} from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
class App extends React.Component {
render() {
return なんでもいい;
}
}
export default DragDropContext(HTML5Backend)(App);少し分かりづらいですが、this.propsの値などは増えたりしないので注意です。
Drag and Drop (dnd)
Drag イベントを設定したいならDragSource、 Drop イベントを設定したいならDropTargetHOCを使います。どちらもreact-dndから提供されています。
共通項目
どちらとも第1引数にはtypeを指定します。これは処理をつなげる為に使われます。Fooというタイプの Draggable 要素をFooというタイプの Droppable 要素へドロップした時に初めてドラッグからドロップという一連の処理が実行されます。
第3引数のconnectはreact-reduxのconnectと同じような動きです。react-dndで管理している状態(state)をコンポーネントのpropsへ渡す為に使います。
第2引数のspecは関数をまとめたオブジェクトを渡します。これらのキー名はreact-dndが指定している名前にする必要があり、その一部は必須項目になっています。
react-dndの関数の引数にあるpropsは HOC の対象となるコンポーネントのpropsの値、monitorsは、react-dnd.github.io/r/d/a/drag-source-monitorにある内容がオブジェクトになった形のものが入っています。propsなどは対象先ですが、monitorsには対象元が入っているような感じです。
DragSource
specには、beginDrag(props, monitor, component), endDrag(props, monitor, component), canDrag(props, monitor), isDragging(props, monitor)が設定でき、beginDragだけは必須項目です。それぞれ、
beginDragはドラッグが始まったタイミングに発火し、endDragはドラッグが終わったタイミングに発火します。beginDragやendDrag戻り値は、monitor.getItem()で取り出せるようになります。
canDragはドラッグできるかの動的制御に使います。
HOC の対象となるコンポーネントでは最小限、connectでconnect.dragSource()を受け取り Drap 対象とするJSX.Elementをその関数でラップする必要があります。
import {DragSource} from 'react-dnd';
DragSource(
'BLOCK',
{
beginDrag(props) {
console.log('beginDrag');
return props;
}
},
connect => {
return {
connectDragSource: connect.dragSource()
};
}
)(
class extends React.Component {
render() {
return this.props.connectDargSource(
);
}
}
);DropTarget
先程 Drop 側のtypeをBLOCKで指定したのでコチラ側もBLOCKを指定します。
こちらのspecは、drop(props, monitor, component), hover(props, monitor, component), canDrop(props, monitor)となっており、canDropは概ねcanDragのものと同じです。
こちらには必須となっている項目はありません。
dropは Dragable 要素を Droppable 要素の上で話した時に実行され、hoverは重なっている間連続で実行されます。
またこちらでは最小限、connectでconnect.dropTarget(),を受け取り Drop 対象とするJSX.Elementをその関数でラップする必要があります。
import {DropTarget} from 'react-dnd';
DropTarget(
'BLOCK',
{
drop(props) {
console.log('drop');
// onDrop は ` {}} />`
// のように渡したもの
// props.onDrop();
}
},
connect => {
return {
connectDrogTarget: connect.dropTarget()
};
}
)(
class extends React.Component {
render() {
return this.props.connectDrogTarget(
);
}
}
); Drag も Drop もできる要素
connect.dragSource()とconnect.drogTarget()2つでラップしてあげればいけます。
const Draggable = DragSource(/* ... */);
const Droppable = DropTarget(/* ... */);
const DNDCompoennt = Droppable(
Droppable(
class extends React.Component {
render() {
const {connectDrogTarget, connectDragSource} = this.props;
return connectDropTarget(
connectDragSource(
)
);
}
}
)
);仕上げ
DragDropContextProviderより深い部分かDragDropContextを適用したコンポーネント以下の部分で使うだけです。
class App extends React.Component {
render() {
return (
{
console.log('drop');
}}
/>
);
}
}